package com.gframework.boot.mvc.filter;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import org.springframework.core.annotation.Order;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;


/**
 * rest方式请求与传统请求中的一些逻辑差异问题处理.
 * <p>例如rest请求通常无法直接处理302重定向，那么本类可以解决此问题将所有的302都修改为rest方式返回。
 * <p>但是并不是所有的重定向都会处理，通常302重定向只是临时重定向，大部分情况都是传统开发中用到的。而对于接口转移，或永久转移等可以使用301或307进行重定向。
 * 
 * @since 1.0.0
 * @author Ghwolf
 */
@Order(Integer.MIN_VALUE + 1_000_000)
public class RestRequestHandleFilter extends OncePerRequestFilter {
	
	public static final String DO_NOT_PROCESS_REDIRECT_REQUEST_KEY = "RestRequestHandleFilter:ignore-redirect-to-rest-body";
	
	/**
	 * 重定向返回值拦截器
	 */
	private final RestRedirectResponseInterceptor interceptor ;
	
	public RestRequestHandleFilter(RestRedirectResponseInterceptor interceptor){
		Assert.notNull(interceptor,"重定向返回值拦截器对象不存在！请检查是否存在RestRedirectResponseInterceptor接口子类bean！");
		this.interceptor = interceptor;
		logger.info("====> 以启用 RestRequestHandleFilter 将对rest请求中存在的特殊问题进行处理！");
	}
	
	/**
	 * 设置忽略当前请求对于返回重定向结果的拦截处理
	 * @param request http请求对象
	 */
	public static void setIgnoreRedirectToRestBodyHandle(HttpServletRequest request){
		request.setAttribute(DO_NOT_PROCESS_REDIRECT_REQUEST_KEY, true);
	}
	
	
	private class RestResponseWrapper extends HttpServletResponseWrapper {

		private static final String LOCATION_HEADER_NAME = "Location";
		
		private boolean doRedirect = false ;
		private String location ;
		private final HttpServletRequest request;
		
		public RestResponseWrapper(HttpServletResponse response,HttpServletRequest request) {
			super(response);
			this.request = request;
		}
		
		@Override
		public void sendRedirect(String location) throws IOException {
			if (request.getAttribute(DO_NOT_PROCESS_REDIRECT_REQUEST_KEY) != null) {
				super.sendRedirect(location);
			} else {
				RestRequestHandleFilter.this.interceptor.response(location, (HttpServletResponse) super.getResponse(),request);
			}
		}
		
		@Override
		public void addHeader(String name, String value) {
			if (LOCATION_HEADER_NAME.equalsIgnoreCase(name)) {
				if (doRedirect) {
					RestRequestHandleFilter.this.interceptor.response(this.location, (HttpServletResponse) super.getResponse(),request);					
				} else {
					this.location = value ;
				}
			} else {
				super.addHeader(name, value);
			}
		}
		
		@Override
		public void setHeader(String name, String value) {
			if (LOCATION_HEADER_NAME.equalsIgnoreCase(name)) {
				if (doRedirect) {
					RestRequestHandleFilter.this.interceptor.response(this.location, (HttpServletResponse) super.getResponse(),request);					
				} else {
					this.location = value ;
				}
			} else {
				super.setHeader(name, value);
			}
		}
		
		@Override
		public void setStatus(int sc) {
			if (sc == 302) {
				if (StringUtils.isEmpty(this.location)) {
					this.doRedirect = true ;
				} else {
					RestRequestHandleFilter.this.interceptor.response(this.location, (HttpServletResponse) super.getResponse(),request);					
				}
			} else {
				super.setStatus(sc);
			}
		}
		
	}
	
	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		filterChain.doFilter(request, new RestResponseWrapper(response,request));
	}

}
